package cn.ztydata.teachingsystem.heaven.web.controller;

import cn.ztydata.teachingsystem.common.Page;
import cn.ztydata.teachingsystem.exception.ServiceException;
import cn.ztydata.teachingsystem.exception.UploadException;
import cn.ztydata.teachingsystem.heaven.common.WebContext;
import cn.ztydata.teachingsystem.heaven.cons.Constants;
import cn.ztydata.teachingsystem.heaven.cons.MsgTemplate;
import cn.ztydata.teachingsystem.heaven.entity.Course;
import cn.ztydata.teachingsystem.heaven.entity.CourseProfile;
import cn.ztydata.teachingsystem.heaven.entity.CourseStatistics;
import cn.ztydata.teachingsystem.heaven.entity.User;
import cn.ztydata.teachingsystem.heaven.service.CourseOverviewService;
import cn.ztydata.teachingsystem.heaven.service.CourseService;
import cn.ztydata.teachingsystem.heaven.service.TeacherTeamService;
import cn.ztydata.teachingsystem.heaven.util.UploadUtil;
import cn.ztydata.teachingsystem.heaven.web.dto.*;
import cn.ztydata.teachingsystem.heaven.web.wrapper.HttpSessionProxy;
import cn.ztydata.teachingsystem.util.StringCodeUtil;
import cn.ztydata.teachingsystem.webservice.result.json.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;

/**
 * 课程-维护控制器类
 * Created by chenxin on 2014/12/10.
 */
@Controller
@RequestMapping("/lesson")
public class LessonController extends BaseController {
    @Autowired
    private CourseOverviewService courseOverviewService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private TeacherTeamService teacherTeamService;

    @Value("${session.key}")
    private String sessionKey;
    @Autowired
    private WebContext webContext;

    /**
     * 获取课程概况内容
     * @param courseId 课程ID
     * @param type 概况类型
     * @return json
     *
     * @author cx
     * @since 2014-12-10
     */
    @RequestMapping(value = "/info/{courseId}/{type}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getLessonInfo(@PathVariable("courseId") long courseId, @PathVariable("type") int type) {
        //校验参数
        Assert.isTrue(courseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "课程ID"));
        Assert.isTrue(type > 0 && type < 9, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "概况类型"));

        //获取课程概况内容
        CourseProfile content = courseOverviewService.getContent(courseId, type);

        log.debug("return 课程概况内容");
        return new JsonResultData<>(mapper.map(content,CourseOverviewDto.class));
    }

    /**
     * 编辑课程概况
     * @param courseOverviewDto 课程概况dto
     * @return json
     *
     * @author cx
     * @since 2014-12-10
     */
    @RequestMapping(value = "/infoEdit", method = RequestMethod.PUT)
    @ResponseBody
    public JsonResult updateOverview(@Valid @RequestBody CourseOverviewDto courseOverviewDto) {
        try {
            //编辑保存
            courseOverviewService.updateContent(courseOverviewDto.getId(), courseOverviewDto.getType(), courseOverviewDto.getContent());
        } catch (ServiceException ex) {
            log.debug("更新课程概况失败");
            return new JsonResult(false, ex.getMessage().isEmpty() ? "保存失败" : ex.getMessage());
        }

        log.debug("更新课程概况成功");
        return new JsonResult(true, "保存成功");
    }

    /**
     * 获取课程列表
     * @param pageNum 页码
     * @param kind 课程种类
     * @param teacherId 教师ID
     * @param keyword 搜索关键字
     * @return json
     *
     * @author cx
     * @since 2014-12-11
     */
    @RequestMapping(value = "/list/{pageNum}/{pageSize}/{kind}/{teacherId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultList<CourseListDto> getCourseList(@PathVariable int pageNum, @PathVariable int pageSize, @PathVariable int kind,
                                                       @PathVariable long teacherId, @RequestParam(value = "search", required = false) String keyword) {
        //校验参数
        Assert.isTrue(pageNum > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "页码"));
        Assert.isTrue(pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "每页条数"));
        Assert.isTrue(kind >= 0 && kind <= 2, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "课程种类"));
        Assert.isTrue(teacherId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "教师ID"));

        //搜索关键字转码
        keyword = StringCodeUtil.urlParamTransCode(keyword, "utf-8");
        //获取课程列表
        Page<Course> page = courseService.getAllForTeacher(pageNum, pageSize, kind, teacherId, StringUtils.trim(keyword));

        //映射到dto类
        Page<CourseListDto> result = new Page<>(page.getTotal(), page.getSize(), page.getNum(),
                mapper.mapList(page.getItems(), CourseListDto.class));

        log.debug("return 课程分页集合");
        return new JsonResultPage<>(result);
    }

    /**
     * 新增课程
     * @param courseDto 课程dto类
     * @return json
     *
     * @author cx
     * @since 2014-12-11
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    public JsonResultId saveCourse(@Valid @RequestBody CourseDto courseDto) {
        //映射到实体类
        Course course = mapper.map(courseDto, Course.class);

        //保存新增的课程
        try {
            courseService.save(course);
        } catch (ServiceException ex) {
            log.debug("保存新增课程失败");
            return new JsonResultId(false, ex.getMessage().isEmpty() ? "保存失败" : ex.getMessage());
        }

        log.debug("保存新增课程成功");
        return new JsonResultId(course.getId(), "保存成功");
    }

    /**
     * 编辑保存课程
     * @param courseDto 课程dto类
     * @return json
     *
     * @author cx
     * @since 2014-12-12
     */
    @RequestMapping(value = "/edit", method = RequestMethod.PUT)
    @ResponseBody
    public JsonResult updateCourse(@Valid @RequestBody CourseDto courseDto) {
        //映射到实体类
        Course course = mapper.map(courseDto, Course.class);

        //编辑保存课程
        try {
            courseService.update(course);
        } catch (ServiceException ex) {
            log.debug("编辑保存课程失败");
            return new JsonResult(false, ex.getMessage().isEmpty() ? "保存失败" : ex.getMessage());
        }

        log.debug("编辑保存课程成功");
        return new JsonResult(true, "保存成功");
    }

    /**
     * 获取课程明细
     * @param courseId 课程ID
     * @return json
     *
     * @author cx
     * @since 2014-12-12
     */
    @RequestMapping(value = "/detail/{courseId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultData<CourseDto> getDetail(@PathVariable long courseId) {
        //校验参数
        Assert.isTrue(courseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, courseId));

        try {
            Course course = courseService.getById(courseId);
            //映射到dto类
            CourseDto result = mapper.map(course, CourseDto.class);

            log.debug("获取课程明细成功");
            return new JsonResultData<>(result);
        } catch (ServiceException ex) {
            log.debug("获取课程明细失败");
            return new JsonResultData<>(false, ex.getMessage().isEmpty() ? "获取课程信息失败" : ex.getMessage());
        }
    }

    /**
     * 上传课程封面
     * @param courseId 课程ID
     * @param coverFile 上传文件
     * @return json
     *
     * @author cx
     * @since 2014-12-13
     */
    @RequestMapping(value = "/cover", method = RequestMethod.POST)
    @ResponseBody
    public JsonResultData<Map<String, String>> uploadCover(@RequestParam("id") long courseId, @RequestParam("imageData") MultipartFile coverFile) {
        //校验参数
        Assert.isTrue(courseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "课程ID"));

        //定义允许上传的图片类型
        List fileTypes = Lists.newArrayList("jpg", "png", "gif", "bmp");
        String url = null;

        try {
            //校验用户是否有权修改课程封面
            teacherTeamService.isMemeber(courseId);

            //校验上传的文件
            UploadUtil.validateFile(coverFile, fileTypes);

            //保存上传的图片
            String saveDir = Constants.UPLOAD_DIR + "/" + "courseCover/";
            String fileExt = UploadUtil.getFileExt(coverFile.getOriginalFilename());
            url = saveDir + UploadUtil.generateFileName(fileExt);

            File file = new File(webContext.getRootDirPath(), url);
            FileUtils.writeByteArrayToFile(file, coverFile.getBytes());

            //保存封面路径
            courseService.updateCover(url, courseId);
        } catch (IOException ex) {
            log.debug("课程封面文件操作异常");
            log.warn("上传课程封面失败:url->" + url, ex);
            return new JsonResultData<>(false, "上传失败");
        } catch (UploadException | ServiceException ex) {
            log.debug("上传课程封面失败");
            return new JsonResultData<>(false, ex.getMessage().isEmpty() ? "上传失败" : ex.getMessage());
        }

        Map<String, String> result = Maps.newHashMap();
        result.put("url", url);

        log.debug("上传课程封面成功");
        return new JsonResultData<>(result, "上传成功");
    }

    /**
     * 获取课程列表-授权课程负责人
     * @param pageNum 页码
     * @param pageSize 每页条数
     * @param specId 专业ID
     * @param keyword 搜索关键字
     * @return json
     *
     * @author cx
     * @since 2014-12-15
     */
    @RequestMapping(value = "/authList/{pageNum}/{pageSize}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultPage<CourseAuthListDto> getAuthList(@PathVariable int pageNum,
                                                     @PathVariable int pageSize,
                                                     @RequestParam(value = "majorId") Long specId,
                                                     @RequestParam String keyword) {
        //校验参数
        if (specId == null) {
            log.debug("specId == null");
            specId = Long.valueOf(0);
        }

        Assert.isTrue(pageNum > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "页码"));
        Assert.isTrue(pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "每页条数"));
        Assert.isTrue(specId >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "专业ID"));

        //搜查关键字转码
        keyword = StringCodeUtil.urlParamTransCode(keyword, "utf-8");

        //获取分页课程列表
        Page<Course> page = courseService.getListForAuth(pageNum, pageSize, specId, keyword);
        //映射到dto类
        Page<CourseAuthListDto> result = new Page<>(page.getTotal(), pageSize, pageNum, mapper.mapList(page.getItems(),
                CourseAuthListDto.class));

        log.debug("获取课程授权列表成功");
        return new JsonResultPage<>(result);
    }

    /**
     * 更新课程层级结构
     * @param structDto dto类
     * @return json
     *
     * @author chenxin
     * @since 2014/12/16
     */
    @RequestMapping(value = "/structEdit", method = RequestMethod.PUT)
    @ResponseBody
    public JsonResult updateStruct(@Valid @RequestBody StructDto structDto) {
        //映射到实体类
        Course course = mapper.map(structDto, Course.class);

        //更新结构
        try {
            courseService.updateCourseStruct(course);
        } catch (ServiceException ex) {
            log.debug("更新层级结构失败");
            return new JsonResultPage<>(false, ex.getMessage().isEmpty() ? "更新失败" : ex.getMessage());
        }

        log.debug("更新层级结构成功");
        return new JsonResult();
    }

    /**
     * 获取课程的层级结构信息
     *
     * @author chenxin
     * @since 2014/12/16
     */
    @RequestMapping(value = "/struct/{courseId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultData<StructDto> getStruct(@PathVariable long courseId) {
        //校验参数
        Assert.isTrue(courseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "课程ID"));

        try {
            //获取层级结构信息
            Course course = courseService.getCourseStruct(courseId);
            //映射到dto类
            StructDto result = mapper.map(course, StructDto.class);

            log.debug("获取层级结构成功");
            return new JsonResultData<>(result);
        } catch (ServiceException ex) {
            log.debug("获取层级结构失败");
            return new JsonResultData<>(false, ex.getMessage());
        }
    }

    /**
     * 获取课程概况的填写状态
     *
     * @author chenxin
     * @since 2014/12/17
     */
    @RequestMapping(value = "/infoCheck/{courseId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultList<Long> getInfoCheck(@PathVariable long courseId) {
        //校验参数
        Assert.isTrue(courseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "课程ID"));

        //获取概况的填写状态
        List<Long> result = courseOverviewService.getForNull(courseId);

        log.debug("获取课程概况的填写状态");
        return new JsonResultList<>(result);
    }

    /**
     * 获取首页-系部-课程
     *
     * @author chenxin
     * @since 2015/1/10
     */
    @RequestMapping(value = "/indexList/{deptId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultList<CourseListDto> getIndexList(@PathVariable long deptId) {
        //校验参数
        Assert.isTrue(deptId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "系部ID"));

        //获取指定系部的两门课程
        List<Course> courseList = courseService.getIndexList(deptId, 2);

        log.debug("获取首页-系部-课程");
        return new JsonResultList<>(mapper.mapList(courseList, CourseListDto.class));
    }

    /**
     * 获取首页-专业-课程列表
     *
     * @author chenxin
     * @since 2015/1/11
     */
    @RequestMapping(value = "/resourceTotal/{specId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultList<CourseStatisticsDto> getRscTotal(@PathVariable long specId) {
        //校验参数
        Assert.isTrue(specId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "专业ID"));

        //获取指定专业下的课程及其资源总数
        List<CourseStatistics> courseStatisticsList = courseService.getIndexListOfSpec(specId, 20);

        log.debug("获取首页-专业-课程列表");
        return new JsonResultList<>(mapper.mapList(courseStatisticsList, CourseStatisticsDto.class));
    }

    /**
     * 课程发布
     * @param id 课程编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-02-06
     */
    @RequestMapping(value = "/publish/{id}", method = RequestMethod.PUT)
    @ResponseBody
    public JsonResult publish(@PathVariable int id){
        //发布课程
        if(courseService.release(id)){
            log.debug("发布课程成功:courseService.release(id)");

            return new JsonResult(true, "课程发布成功");
        }

        log.debug("发布课程失败:!courseService.release(id)");

        return new JsonResult(false, "课程发布失败");
    }

    /**
     * 课程下拉框
     * @param role 权限(0:教师、1：学生)
     * @param request 请求
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-06
     */
    @ResponseBody
    @RequestMapping(value = "/comboList/{role}", method = RequestMethod.GET)
    public JsonResult comboList(@PathVariable int role,HttpServletRequest request) {
        //校验参数
        Assert.isTrue(role == 0 || role == 1, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "角色"));

        HttpSessionProxy httpSessionProxy = (HttpSessionProxy) request.getSession();

        List<Course> courses = courseService.getListForTeacherOrStudent((User) httpSessionProxy.getAttribute(sessionKey), role);

        return new JsonResultList<>(mapper.mapList(courses, CourseDto.class));
    }

    /**
     * 学生在学课程
     * @param type 1必修课 2选修课
     * @param studentId 学生ID
     * @param page 页数
     * @param pageSize 条数
     * @return json
     *
     * @author wyh
     * @since 2015-04-02
     */
    @RequestMapping(value = "/studentCurrent", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultPage<CourseListDto> listStudentCourse(@RequestParam int type,
                                                           @RequestParam long studentId,
                                                           @RequestParam int page,
                                                           @RequestParam int pageSize){
        Assert.isTrue(type == 1 || type == 2, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "课程类型"));
        Assert.isTrue(studentId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "学生ID"));
        Assert.isTrue(page > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "当前页码"));
        Assert.isTrue(pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "每页条数"));

        Page<Course> coursePage = courseService.listStudentCourse(type, studentId, page, pageSize);

        log.debug("返回 学生在学课程");
        return new JsonResultPage<>(new Page<>(coursePage.getTotal(), coursePage.getSize(), coursePage.getNum(), mapper.mapList(coursePage.getItems(), CourseListDto.class)));
    }
}
